#pragma once

#include <iostream>
#include <memory>
#include <queue>
#include <vector>

#include "Thread.hpp"
#include "Mutex.hpp"
#include "Cond.hpp"

const static int threadnum_default = 3; // for debug

// 单例线程池
template <typename T>
class ThreadPool
{
private:
    bool QueueIsEmpty()
    {
        return _q.empty();
    }
    void Routine(const std::string &name)
    {
        // LOG(LogLevel::INFO) << name << " hello world";
        while (true) // 死循环
        {
            // 把任务从线程获取到线程私有  临界区 -> 私有栈
            T t;
            {
                LockGuard lockguard(&_lock);
                while (QueueIsEmpty() && _isrunning)
                {
                    _thread_wait_num++;
                    _cond.Wait(_lock);
                    _thread_wait_num--;
                }
                // T t = _q.front();   // 处理任务不需要再临界区，只需把取任务保护好就行
                if (!_isrunning && QueueIsEmpty()) // 退出情况设计
                {
                    LOG(LogLevel::INFO) << "线程池退出 && 任务队列为空， " << name << "退出";
                    break;
                }

                t = _q.front();
                _q.pop();
                // t();
            }
            t();  // 处理任务
        }
    }
    ThreadPool(int threadnum = threadnum_default) : _threadnum(threadnum), _thread_wait_num(0), _isrunning(false) // 对象先创建（存在），再初始化
    {
        for (int i = 0; i < threadnum; i++)
        {
            // 方法1
            // auto f = std::bind(hello, this);

            // 方法2
            std::string name = "thread-" + std::to_string(i + 1);
            _threads.emplace_back(Thread([this](const std::string &name)
                                         { this->Routine(name); }, name));

            // Thread t([this]() {

            // }, name);
            // _threads.push_back(std::move(t));
        }
        LOG(LogLevel::INFO) << " threadpool cerate success";
    }

    // 复制拷⻉禁⽤
    ThreadPool<T> &operator=(const ThreadPool<T> &) = delete;
    ThreadPool(const ThreadPool<T> &) = delete;

public:
    void Start()
    {
        if (_isrunning)
            return;
        _isrunning = true;
        for (auto &t : _threads)
        {
            t.Start();
        }
        LOG(LogLevel::INFO) << " threadpool start success";
    }

    // 退出逻辑设计
    // 1.如果被唤醒 && 队列没有任务 = 让线程退出
    // 2.如果被唤醒 && 队列有任务 = 线程不能立即退出 而应该让线程把任务处理完，再退出
    // 3.线程本身没有休眠 我们应该让他把能处理的任务全处理完成，再退出
    void Stop()
    {
        // 这种做法太简单粗暴
        // if (!_isrunning)
        //     return;
        // _isrunning = false;
        // for (auto &t : _threads)
        // {
        //     t.Stop();
        // }
        // LOG(LogLevel::INFO) << " threadpool stop success";
        if (!_isrunning)
            return;
        _isrunning = false;
        if (_thread_wait_num > 0)
            _cond.NotifyAll();
    }
    void Wait()
    {
        for (auto &t : _threads)
        {
            t.Join();
        }
        LOG(LogLevel::INFO) << " threadpool wait success";
    }
    void Enqueue(const T &in)
    {
        if (!_isrunning)
            return;
        {
            LockGuard lockguard(&_lock);
            _q.push(in);
            if (_thread_wait_num > 0)
                _cond.NotifyOne();
        }
    }
    //  获取单例   //  让用户以类的方式访问构造单例，不需要自己构造
    static ThreadPool<T> *GetInstance()
    {
        if(!_instance)
        {
            LockGuard LockGuard(&_singleton_lock);
            if (!_instance)
            {
                LOG(LogLevel::DEBUG) << "线程池首次被使用,创建并初始化";

                _instance = new ThreadPool<T>();
                _instance->Start();
            }
            // else
            // {
            //     LOG(LogLevel::DEBUG) << "线程池单例已经存在，直接获取";
            // }
        }
        return _instance;
    }
    ~ThreadPool()
    {
        LOG(LogLevel::INFO) << " threadpool destory success";
    }

private:
    // 任务队列
    std::queue<T> _q; //  整体使用的临界资源

    // 多个线程
    std::vector<Thread> _threads;
    int _threadnum;
    int _thread_wait_num;
    // 锁
    Mutex _lock;
    // 条件变量
    Cond _cond;

    bool _isrunning; // 防止线程池重复启动

    // 单例中静态指针   // 懒汉模式设计
    static ThreadPool<T> *_instance;
    static Mutex _singleton_lock;
};

template <class T>
ThreadPool<T> *ThreadPool<T>::_instance = nullptr;

template <class T>
Mutex ThreadPool<T>::_singleton_lock;